﻿using Ardalis.GuardClauses;
using CleanArchitecture.Core.Configuration;
using CleanArchitecture.Core.Helper;
using CleanArchitecture.Infrastructure.ActiveLogExtension;
using CleanArchitecture.Infrastructure.AutoMapper;
using CleanArchitecture.Infrastructure.Entities;
using CleanArchitecture.Infrastructure.Entities.Business;
using CleanArchitecture.Infrastructure.Entities.Common;
using CleanArchitecture.Infrastructure.Entities.Settings;
using CleanArchitecture.Infrastructure.Interfaces;
using CleanArchitecture.Infrastructure.Interfaces.Business;
using CleanArchitecture.Infrastructure.Interfaces.Common;
using CleanArchitecture.Infrastructure.Interfaces.Media;
using CleanArchitecture.Infrastructure.Models;
using CleanArchitecture.Infrastructure.Models.Business.Advertises;
using CleanArchitecture.Infrastructure.Models.Business.Blog;
using CleanArchitecture.Infrastructure.Models.Business.Columns;
using CleanArchitecture.Infrastructure.Models.Business.Comments;
using CleanArchitecture.Infrastructure.Models.Business.FileUpload;
using CleanArchitecture.Infrastructure.Models.Business.News;
using NUglify.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CleanArchitecture.Web.Factories
{
    public partial class BusinessModelFactory : IBusinessModelFactory
    {
        #region Fields
        private readonly INewsService _newsService;
        private readonly IBlogService _blogService;
        private readonly IDateTimeHelper _datetimeHelper;
        private readonly IColumnService _columnService;
        private readonly NewsSettings _newsSettings;
        private readonly BlogSettings _blogSettings;
        private readonly IFileUploadService _fileuploadService;
        private readonly IAdvertiseService _advertiseService;
        private readonly ICommentService _commentService;
        private readonly IGenericAttributeService _gaService;
        #endregion

        #region Ctor

        public BusinessModelFactory(INewsService newsService,
            IBlogService blogService,
            IDateTimeHelper datetimeHelper,
            IColumnService columnService,
            NewsSettings newsSettings,
            BlogSettings blogSettings,
            IFileUploadService fileuploadService,
            IAdvertiseService advertiseService,
            ICommentService commentService,
            IGenericAttributeService gaService)
        {
            _newsService = newsService;
            _blogService = blogService;
            _datetimeHelper = datetimeHelper;
            _columnService = columnService;
            _newsSettings = newsSettings;
            _blogSettings = blogSettings;
            _fileuploadService = fileuploadService;
            _advertiseService = advertiseService;
            _commentService = commentService;
            _gaService = gaService;
        }

        #endregion

        #region Column
        /// <summary>
        /// 根据栏目菜单Id获取从该菜单到最顶级父节点菜单完整面包屑数据组
        /// </summary>
        /// <param name="cid"></param>
        /// <returns></returns>
        public virtual IList<ColumnItemModel> GetColumnBreadcrumb(int cid)
        {
            if (cid <= 0) return new List<ColumnItemModel>();
            var columns = _columnService.GetColumnList();
            var breadcrumbList = new List<ColumnItemModel>();
            FindParentColumnItem(item => { breadcrumbList.Add(item); }, cid, columns);
            return breadcrumbList;
        }
        private void FindParentColumnItem(Action<ColumnItemModel> item, int cid, IList<ColumnItemModel> columns)
        {
            var CurrentItem = columns.FirstOrDefault(c => c.Id == cid);
            if (CurrentItem != null) item(CurrentItem);
            if (CurrentItem.ParentId > 0) FindParentColumnItem(item, CurrentItem.ParentId, columns);
        }

        public virtual bool ColumnHasChild(int cid)
        {
            var columns = _columnService.GetColumnList();
            return columns.Any(c => c.ParentId == cid);
        }

        public virtual IList<ColumnTreeItemModel> PrepareAuthorizedColumnItemTreeModel(int[] roleIds, int LanguageId = 0, int columntype = 0)
        {
            var columns = _columnService.GetColumnListByRoleIds(roleIds);
            if (columns == null) return null;
            if (LanguageId > 0)
            {
                columns = columns.Where(c => c.LanguageId == LanguageId).ToList();
                if (columns == null) return null;
            }
            if (columntype > 0 && Enum.IsDefined(typeof(EntityEnumConfig.ColumnType), columntype))
            {
                columns = columns.Where(c => c.ColumnType == (EntityEnumConfig.ColumnType)columntype).ToList();
                if (columns == null) return null;
            }
            return PackageColumnTreeNode(columns.Where(t => t.ParentId == 0).OrderBy(t => t.DisplayOrder).ToList(), columns, false);
        }

        public virtual IList<ColumnTreeItemModel> PrepareColumnItemTreeModel(int LanguageId = 0, int columntype = 0, bool layout = false)
        {
            var columns = _columnService.GetColumnList();
            if (columns == null) return null;
            if (LanguageId > 0)
            {
                columns = columns.Where(c => c.LanguageId == LanguageId).ToList();
                if (columns == null) return null;
            }
            if (columntype > 0 && Enum.IsDefined(typeof(EntityEnumConfig.ColumnType), columntype))
            {
                columns = columns.Where(c => c.ColumnType == (EntityEnumConfig.ColumnType)columntype).ToList();
                if (columns == null) return null;
            }
            return PackageColumnTreeNode(columns.Where(t => t.ParentId == 0).OrderBy(t => t.DisplayOrder).ToList(), columns, layout);
        }

        private IList<ColumnTreeItemModel> PackageColumnTreeNode(IList<ColumnItemModel> iterators, IList<ColumnItemModel> records, bool layout = false)
        {
            if (iterators == null || iterators.Count <= 0)
                return null;

            var nodes = new List<ColumnTreeItemModel>();
            IList<ColumnTreeItemModel> childrens = null;
            foreach (var item in iterators)
            {
                var menu = new ColumnTreeItemModel
                {
                    title = item.Name,
                    id = item.Id,
                    pid = item.ParentId,
                    language = item.LanguageName,
                    url = item.UrlRoute,
                    level = item.Level,
                    displayorder = item.DisplayOrder,
                    layouttype = string.Empty,
                    layoutlisttemplate = string.Empty,
                    layoutdetailtemplate = string.Empty
                };
                if (layout)
                {
                    switch (item.LayoutType)
                    {
                        case EntityEnumConfig.PageLayoutType.ArticleList:
                            menu.layouttype = "列表";
                            menu.layoutlisttemplate = PageAvailableLayoutTemplate.AvailableListLayout.Single(t => t.Value == item.LayoutListTemplate).Text;
                            menu.layoutdetailtemplate = PageAvailableLayoutTemplate.AvailableDetailLayout.Single(t => t.Value == item.LayoutDetailTemplate).Text;
                            break;
                        case EntityEnumConfig.PageLayoutType.SingleDetailPage:
                            menu.layouttype = "详情页";
                            menu.layoutlisttemplate = "无";
                            menu.layoutdetailtemplate = PageAvailableLayoutTemplate.AvailableDetailLayout.Single(t => t.Value == item.LayoutDetailTemplate).Text;
                            break;
                        default:
                            menu.layouttype = "未定义";
                            menu.layoutlisttemplate = menu.layoutdetailtemplate = "未知布局";
                            break;
                    }
                }
                if (records.Any(r => r.ParentId == item.Id))
                {
                    childrens = PackageColumnTreeNode(records.Where(r => r.ParentId == item.Id).ToList(), records, layout);
                    menu.children = menu.children.Concat(childrens.OrderBy(c => c.displayorder)).ToList();
                }
                nodes.Add(menu);
            }
            return nodes;
        }
        /// <summary>
        /// 创建编辑栏目菜单所需要数据结构
        /// 当id==0时 创建新栏目菜单初始数据
        /// </summary>
        /// <param name="cid"></param>
        /// <returns></returns>
        public virtual ColumnItemModel PrepareColumnItemModel(int cid = 0)
        {
            if (cid == 0)
            {
                var item = new ColumnItemModel
                {
                    ParentId = 0,
                    ColumnType = EntityEnumConfig.ColumnType.NewsColumn,
                    Level = 1,
                    IsDisplay = EntityEnumConfig.YesorNo.YES,
                    UrlTarget = EntityEnumConfig.UrlTarget.Self,
                    IsActive = EntityEnumConfig.YesorNo.YES,
                    DisplayOrder = 1,
                    LayoutType = EntityEnumConfig.PageLayoutType.ArticleList,
                    LayoutDetailTemplate = PageAvailableLayoutTemplate.AvailableDetailLayout[0].Value,
                    LayoutListTemplate = PageAvailableLayoutTemplate.AvailableListLayout[0].Value
                };
                return item;
            }
            var record = _columnService.GetColumnById(cid);
            if (record == null) return null;
            var itemModel = record.ToModel<ColumnItemModel>();
            return itemModel;
        }
        /// <summary>
        /// 前端接口调用，用于过滤有菜单栏目是否在前端不显示
        /// </summary>
        /// <param name="LangugeId"></param>
        /// <returns></returns>
        public virtual IList<ColumnItemModel> PrepareColumnItemModelsForFront(int LanguageId)
        {
            if (LanguageId <= 0) return null;
            var columns = _columnService.GetColumnList();
            return columns.Where(c => c.LanguageId == LanguageId && c.IsDisplay == EntityEnumConfig.YesorNo.YES).ToList();
        }
        #endregion

        #region News
        /// <summary>
        /// Convert dates to the user time
        /// </summary>
        /// <param name="model"></param>
        /// <param name="entity"></param>
        private void Convert2LocalTime(NewsItem source, ref NewsItemModel dest)
        {
            if (source.StartTaskTimeUtc.HasValue)
                dest.StartTaskTime = _datetimeHelper.ConvertToUserTime(source.StartTaskTimeUtc.Value, DateTimeKind.Local);
            dest.UpdatedOnTime = _datetimeHelper.ConvertToUserTime(source.UpdatedOnTimeUtc, DateTimeKind.Local);
            dest.CreatedOnTime = _datetimeHelper.ConvertToUserTime(source.CreatedOnTimeUtc, DateTimeKind.Local);
        }
        /// <summary>
        /// Prepare paged news item list model
        /// </summary>
        /// <param name="searchModel">News item search model</param>
        /// <param name="keepContents">默认:false,是否保留列表文章</param>
        /// <returns>News item list model</returns>
        public virtual NewsItemListModel PrepareNewsItemListModel(NewsItemSearchModel searchModel, bool keepContents = false)
        {
            //get news items
            var newsItems = _newsService.GetNewsItemsByPage(searchModel.ColumnId, searchModel.RoleIds, searchModel.Page - 1, searchModel.PageSize);

            //prepare list model
            var model = new NewsItemListModel().PrepareToGrid(newsItems, () =>
            {
                return newsItems.Select(newsItem =>
                {
                    //fill in model values from the entity
                    var newsItemModel = newsItem.ToModel<NewsItemModel>();

                    if (!keepContents)
                        //little performance optimization: ensure that "Full" is not returned
                        newsItemModel.Contents = string.Empty;

                    Convert2LocalTime(newsItem, ref newsItemModel);
                    //fill in additional values (not existing in the entity)
                    newsItemModel.IdHash = newsItem.Id.IdEncode();
                    newsItemModel.ColumnIdHash = newsItem.FKColumnId.IdEncode();
                    return newsItemModel;
                });
            });
            model.NewsSettingsModel = _newsSettings.ToSettingsModel<NewsSettingsModel>();
            return model;
        }
        /// <summary>
        /// 前端展示页面根据栏目菜单Id获取每个栏目下前N条文章信息
        /// 与PrepareNewsItemByColumnIdsForFront区别在于：
        /// PrepareNewsItemByColumnIdsForFront 只获取发布日期最新的前N条记录
        /// PrepareNewsItemByEachColumnIdForFront 首先获取每个栏目下推荐置顶的前N条记录
        /// 当推荐置顶记录不够前N条时，获取最新发布的记录补足
        /// </summary>
        /// <param name="columnIds"></param>
        /// <param name="topN"></param>
        /// <param name="keepContents"></param>
        /// <returns></returns>
        public virtual IDictionary<int, List<NewsItemModel>> PrepareNewsItemByEachColumnIdForFront(int[] columnIds, int topN = 1, bool keepContents = false)
        {
            if (columnIds == null) Guard.Against.Null(columnIds, nameof(columnIds));
            var newsItems = _newsService.GetRecommendNewsItemsByColumnIds(columnIds, topN);
            if (newsItems == null) return null;
            var itemsDict = newsItems.GroupBy(n => n.FKColumnId).ToDictionary(x => x.First().FKColumnId, y =>
            {
                var modelList = new List<NewsItemModel>();
                if (y == null) return modelList;
                var columnNewsItems = y.ToList();
                columnNewsItems.ForEach(entity =>
                {
                    if (!keepContents) entity.Contents = string.Empty;
                    var itemModel = entity.ToModel<NewsItemModel>();
                    Convert2LocalTime(entity, ref itemModel);
                    itemModel.IdHash = entity.Id.IdEncode();
                    itemModel.ColumnIdHash = entity.FKColumnId.IdEncode();
                    modelList.Add(itemModel);
                });
                return modelList;
            });
            if (itemsDict.Keys.Count < columnIds.Length)
            {
                foreach (var itemId in columnIds)
                {
                    if (itemsDict.ContainsKey(itemId)) continue;
                    else itemsDict.Add(itemId, new List<NewsItemModel>());
                }
            }
            //For C# 7.0 Above
            foreach (var (colId, modelList) in itemsDict)
            {
                bool addItems = false;
                int listCount = 0;
                int[] exsitsItemIds = null;
                if (modelList == null)
                {
                    addItems = true;
                    listCount = 0;
                    exsitsItemIds = null;
                }
                else if (modelList.Count < topN)
                {
                    addItems = true;
                    listCount = modelList.Count;
                    exsitsItemIds = modelList.Select(m => m.Id).ToArray();
                }
                //else No Actions
                if (addItems)
                {
                    var entities = _newsService.GetNewsItemListByColumnId(colId, topN - listCount, exsitsItemIds);
                    if (entities == null) continue;
                    entities.ForEach(item =>
                    {
                        if (!keepContents) item.Contents = string.Empty;
                        var itemModel = item.ToModel<NewsItemModel>();
                        Convert2LocalTime(item, ref itemModel);
                        itemModel.IdHash = item.Id.IdEncode();
                        itemModel.ColumnIdHash = item.FKColumnId.IdEncode();
                        modelList.Add(itemModel);
                    });
                }
            }
            return itemsDict;
        }
        /// <summary>
        /// 前端展示页面根据栏目菜单Id获取每个栏目下前N条文章信息
        /// </summary>
        /// <param name="columnIds">Arrays of Column Id</param>
        /// <param name="topN">Number of NewsItem of each group column, Default: 1</param>
        /// <param name="keepContents">Is Contain Contents of NewsItem</param> 
        public virtual IList<NewsItemModel> PrepareNewsItemByColumnIdsForFront(int[] columnIds, int topN = 1, bool keepContents = false)
        {
            //get news items
            var newsItems = _newsService.GetNewsItemsByColumnIds(columnIds, topN);
            IList<NewsItemModel> newsItemModels = null;
            if (newsItems != null)
            {
                newsItemModels = new List<NewsItemModel>();
                newsItems.ForEach((item) =>
                {
                    if (!keepContents)
                        item.Contents = string.Empty;
                    var newsItemModel = item.ToModel<NewsItemModel>();
                    Convert2LocalTime(item, ref newsItemModel);
                    //fill in additional values (not existing in the entity)
                    newsItemModel.IdHash = item.Id.IdEncode();
                    newsItemModel.ColumnIdHash = item.FKColumnId.IdEncode();
                    newsItemModels.Add(newsItemModel);
                });
            }

            return newsItemModels;
        }

        public virtual NewsItemModel PrepareNewsItemModel(int newsItemId = 0)
        {
            NewsItemModel model;
            if (newsItemId == 0) // Create
            {
                model = new NewsItemModel();
                model.initItemModel();
                model.UpdatedOnTime = model.CreatedOnTime = _datetimeHelper.ConvertToUserTime(DateTime.Now, DateTimeKind.Local);
            }
            else
            {
                var newsItemEntity = _newsService.GetNewsItemById(newsItemId);
                model = newsItemEntity.ToModel<NewsItemModel>();
                Convert2LocalTime(newsItemEntity, ref model);
            }

            return model;

        }

        /// <summary>
        /// 前端页面根据栏目Id获取其对应的文章内容
        /// 适用于栏目为单页内容展示
        /// </summary>
        /// <param name="columnId"></param>
        /// <returns></returns>
        public virtual NewsItemModel PrepareColumnNewsItemModelForFront(int columnId)
        {
            if (columnId <= 0) return null;
            var newsEntity = _newsService.GetNewsItemByColumnId(columnId);
            if (newsEntity == null) return null;
            var newsItemModel = newsEntity.ToModel<NewsItemModel>();
            Convert2LocalTime(newsEntity, ref newsItemModel);
            GetNewsItemModelExtraInfo(ref newsItemModel);
            return newsItemModel;
        }
        /// <summary>
        /// 前端页面具体文章信息获取
        /// 与PrepareNewsItemModel方法区别在于封装了对于页面展示所需要的额外信息
        /// </summary>
        /// <param name="newsItemId"></param>
        /// <returns></returns>
        public virtual NewsItemModel PrepareNewsItemModelForFront(int newsItemId)
        {
            if (newsItemId <= 0) return null;
            var newsItemModel = PrepareNewsItemModel(newsItemId);
            if (newsItemModel == null) return null;
            else if (!newsItemModel.IsActive) return null;

            GetNewsItemModelExtraInfo(ref newsItemModel);
            return newsItemModel;

        }
        //图片相册,视频列表，文件列表，音频列表查询
        private void GetNewsItemModelExtraInfo(ref NewsItemModel newsItemModel)
        {
            IList<GenericAttribute> newsItemExtraInfo = _gaService.GetAttributesForEntity(newsItemModel.Id, nameof(NewsItem));
            if (newsItemExtraInfo != null)
            {
                IList<FileUpload> fileList = null;
                int[] fileIds = null;
                foreach (var attribute in newsItemExtraInfo)
                {
                    CommonHelper.SetProperty(newsItemModel, attribute.Key, attribute.Value);
                    if (attribute.Key.IndexOf("Ids") > 0)
                    {
                        fileIds = attribute.Value.Split(',').Select(Int32.Parse).ToArray();
                        fileList = _fileuploadService.GetFileUploadList(fileIds);
                        string propName = attribute.Key.Substring(0, attribute.Key.IndexOf("Ids")) + "Urls";
                        CommonHelper.SetProperty(newsItemModel, propName, fileList.Select(f => _fileuploadService.GetFileUrl(f)).ToList());
                        newsItemModel.FileTitles = fileList.Select(f => string.IsNullOrEmpty(f.TitleAttribute) ? f.SeoFilename : f.TitleAttribute).ToList();
                    }
                }
            }
        }
        #endregion

        #region Blog
        /// <summary>
        /// Convert dates to the user time
        /// </summary>
        /// <param name="model"></param>
        /// <param name="entity"></param>
        private void Convert2LocalTime(BlogItem source, BlogItemModel dest)
        {
            if (source.StartTaskTimeUtc.HasValue)
                dest.StartTaskTime = _datetimeHelper.ConvertToUserTime(source.StartTaskTimeUtc.Value, DateTimeKind.Local);
            dest.UpdatedOnTime = _datetimeHelper.ConvertToUserTime(source.UpdatedOnTimeUtc, DateTimeKind.Local);
            dest.CreatedOnTime = _datetimeHelper.ConvertToUserTime(source.CreatedOnTimeUtc, DateTimeKind.Local);
        }
        /// <summary>
        /// Prepare paged Blog item list model
        /// </summary>
        /// <param name="searchModel">Blog item search model</param>
        /// <returns>Blog item list model</returns>
        public virtual BlogItemListModel PrepareBlogItemListModel(BlogItemSearchModel searchModel)
        {
            //get blog items
            var blogItems = _blogService.GetBlogItemsByPage(searchModel.ColumnId, searchModel.RoleIds, searchModel.Page - 1, searchModel.PageSize);
            string defaultImgUrl = "0;" + _fileuploadService.GetDefaultFileUrl();
            //prepare list model
            var model = new BlogItemListModel().PrepareToGrid(blogItems, () =>
            {
                return blogItems.Select(blogItem =>
                {
                    //fill in model values from the entity
                    var blogItemModel = blogItem.ToModel<BlogItemModel>();

                    //little performance optimization: ensure that "Full" is not returned
                    blogItemModel.Contents = string.Empty;

                    Convert2LocalTime(blogItem, blogItemModel);
                    //fill in additional values (not existing in the entity)
                    if (string.IsNullOrEmpty(blogItemModel.CoverImageUrl))
                        blogItemModel.CoverImageUrl = defaultImgUrl;

                    return blogItemModel;
                });
            });
            model.BlogSettingsModel = _blogSettings.ToSettingsModel<BlogSettingsModel>();
            return model;
        }
        /// <summary>
        /// 前后台公用获取博客详情数据，前端访问页面时记录用户浏览博客行为日志，后台系统则不用记录
        /// </summary>
        /// <param name="blogItemId"></param>
        /// <param name="logvisitActivity"></param>
        /// <returns></returns>
        public virtual BlogItemModel PrepareBlogItemModel(int blogItemId = 0, bool logvisitActivity = false)
        {
            BlogItemModel model;
            if (blogItemId == 0) // Create
            {
                model = new BlogItemModel();
                model.initItemModel();
                model.UpdatedOnTime = model.CreatedOnTime = _datetimeHelper.ConvertToUserTime(DateTime.Now, DateTimeKind.Local);
            }
            else
            {
                var blogItemEntity = _blogService.GetBlogItemById(blogItemId);
                if (blogItemEntity == null) return null;
                model = blogItemEntity.ToModel<BlogItemModel>();
                Convert2LocalTime(blogItemEntity, model);
                if (logvisitActivity) blogItemEntity.LogVisitBlogEvent();
            }

            return model;

        }
        /// <summary>
        /// 当导航栏目菜单为单页详情页面时，返回栏目对应的博文详情
        /// </summary>
        /// <param name="columnid"></param>
        /// <param name="logvisitActivity">是否记录浏览博客日志</param>
        /// <returns></returns>
        public virtual BlogItemModel GetBlogItemModelForSinglePageColumn(int columnid, bool logvisitActivity = false)
        {
            BlogItem blogEntity = _blogService.GetBlogItemForSinglePageColumn(columnid);
            if (blogEntity == null) return null;
            var blogModel = blogEntity.ToModel<BlogItemModel>();
            Convert2LocalTime(blogEntity, blogModel);
            if (logvisitActivity) blogEntity.LogVisitBlogEvent();
            return blogModel;
        }
        #endregion

        #region ResourceManage
        /// <summary>
        /// Prepare paged news item list model
        /// </summary>
        /// <param name="searchModel">News item search model</param>
        /// <returns>News item list model</returns>
        public virtual FileItemListModel PrepareFileItemListModel(FileItemSearchModel searchModel)
        {
            //get resource items
            FileType[] fileTypes = null;
            if (searchModel.fileTypes != null) fileTypes = searchModel.fileTypes;
            var fileItems = _fileuploadService.GetFileList(fileTypes, searchModel.Page - 1, searchModel.PageSize);

            //prepare list model
            var model = new FileItemListModel().PrepareToGrid(fileItems, () =>
            {
                UploadUseCategory usecase = new UploadUseCategory();
                return fileItems.Select(fileItem =>
                {
                    //fill in model values from the entity
                    var fileitemModel = fileItem.ToModel<FileItemModel>();

                    fileitemModel.VirtualUrl = _fileuploadService.GetFileUrl(fileItem);

                    fileitemModel.Category = usecase.GetPropertyValue<string>(fileItem.Category);
                    //fill in additional values (not existing in the entity)

                    return fileitemModel;
                });
            });
            return model;
        }

        public virtual FileItemModel PrepareFileItemModel(int fileid)
        {
            //get resource items
            if (fileid == 0) return new FileItemModel();
            UploadUseCategory usecase = new UploadUseCategory();
            var fileEntity = _fileuploadService.GetFileUploadEntityById(fileid);
            var fileItem = fileEntity.ToModel<FileItemModel>();
            fileItem.VirtualUrl = _fileuploadService.GetFileUrl(fileEntity);
            fileItem.Category = usecase.GetPropertyValue<string>(fileItem.Category);
            return fileItem;
        }
        #endregion

        #region AdvertiseManager
        public virtual AdvertiseBannerListModel PrepareAdvertiseBannerListModel(AdvertiseBannerSearchModel searchModel)
        {
            var advItems = _advertiseService.GetAdvertiseBannerItemsByPage(searchModel.Page - 1, searchModel.PageSize);

            //prepare list model
            var model = new AdvertiseBannerListModel().PrepareToGrid(advItems, () =>
            {
                return advItems.Select(advItem =>
                {
                    //fill in model values from the entity
                    var itemModel = advItem.ToModel<AdvertiseBannerModel>();

                    //little performance optimization: ensure that "Full" is not returned
                    itemModel.ItemsJson = string.Empty;
                    itemModel.AdvBannerDescription = string.Empty;

                    if (advItem.StartTimeUtc.HasValue)
                        itemModel.StartTime = _datetimeHelper.ConvertToUserTime(advItem.StartTimeUtc.Value, DateTimeKind.Local);
                    if (advItem.EndTimeUtc.HasValue)
                        itemModel.EndTime = _datetimeHelper.ConvertToUserTime(advItem.EndTimeUtc.Value, DateTimeKind.Local);

                    return itemModel;
                });
            });
            return model;
        }

        public virtual AdvertiseBannerModel PrepareAdvertiseBannerModel(int entityId)
        {
            if (entityId == 0) return new AdvertiseBannerModel
            {
                AdvBannerDisplayType = EntityEnumConfig.AdertiseDisplay.PC,
                AdvBannerType = EntityEnumConfig.AdertiseType.CarouselImages,
                ItemsJson = string.Empty
            };
            var advEntity = _advertiseService.GetAdvertiseEntityById(entityId);
            if (advEntity == null) return null;
            var itemModel = advEntity.ToModel<AdvertiseBannerModel>();
            if (advEntity.StartTimeUtc.HasValue)
                itemModel.StartTime = _datetimeHelper.ConvertToUserTime(advEntity.StartTimeUtc.Value, DateTimeKind.Local);
            if (advEntity.EndTimeUtc.HasValue)
                itemModel.EndTime = _datetimeHelper.ConvertToUserTime(advEntity.EndTimeUtc.Value, DateTimeKind.Local);
            if (string.IsNullOrEmpty(itemModel.ItemsJson))
                itemModel.ItemsJson = string.Empty;  //确保初始数据不为null
            return itemModel;
        }
        #endregion

        #region Comment
        public virtual CommentListModel PrepareCommentListModel(CommentSearchModel searchModel)
        {
            var commentItems = _commentService.GetCommentItemsByPage(searchModel);

            //prepare list model
            var model = new CommentListModel().PrepareToGrid(commentItems, () =>
            {
                return commentItems.Select(cmtItem =>
                {
                    //fill in model values from the entity
                    var itemModel = cmtItem.ToModel<CommentItemModel>();
                    itemModel.ContactName = string.IsNullOrEmpty(itemModel.ContactName)
                                          ? ""
                                          : itemModel.ContactName;
                    itemModel.CreatedTime = _datetimeHelper.ConvertToUserTime(cmtItem.CreatedOnTimeUtc);

                    return itemModel;
                });
            });
            return model;
        }
        #endregion
    }
}
